package cn.gene.timeyan.article.webapi.service.impl;

import cn.gene.timeyan.article.service.CommentService;
import cn.gene.timeyan.article.webapi.mapper.ArticleMapper;
import cn.gene.timeyan.article.webapi.mapper.CommentMapper;
import cn.gene.timeyan.common.constant.RedisConstants;
import cn.gene.timeyan.common.exception.TimeyanServiceException;
import cn.gene.timeyan.common.restful.ResponseCode;
import cn.gene.timeyan.common.utils.FormUtils;
import cn.gene.timeyan.pojo.article.dto.CommentDTO;
import cn.gene.timeyan.pojo.article.model.Comment;
import cn.gene.timeyan.pojo.article.vo.CommentVO;
import cn.gene.timeyan.pojo.ums.vo.UserSimpleVO;
import cn.gene.timeyan.ums.service.IUserDetailService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 鏂囩珷璇勮?淇℃伅 服务实现类
 * </p>
 *
 * @author LWG
 * @since 2022-07-25
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @DubboReference
    private IUserDetailService dubboUserDetails;
    //默认显示模式按照点赞数降序
    private static final String MODEL="like";
    /**
     * 设置某一条评论的显示
     * @param id
     */
    @Override
    public void display(String id) {
        int rows=commentMapper.display(id);
        if (rows<1){
            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"设置失败，请稍后重试");
        }
    }
    /**
     * 设置某一条评论的隐藏
     * @param id
     */
    @Override
    public void hide(String id) {
        int rows=commentMapper.hide(id);
        if (rows<1){
            throw new TimeyanServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"设置失败，请稍后重试");
        }
    }
    /**
     * 除开预热的30条外，另外加载评论
     * @param article_id
     * @return
     */
    @Override
    public List<CommentVO> listByArticleId(Long article_id,String model,Integer page,Integer pageSize) {
        String key="articleDetails:"+article_id+":comment";
        List<CommentVO> commentVOS=new ArrayList<>();
        //有缓存
        if (redisTemplate.hasKey(key+"Like")&&redisTemplate.hasKey(key+"Time")&&redisTemplate.hasKey(key)){
            if (redisTemplate.opsForZSet().size(key+":commentLike")<page*pageSize){
                //数据不够查询新数据
                PageHelper.startPage(page,pageSize);
                List<CommentVO> like=commentMapper.listByArticleIdLike(article_id);
                PageHelper.startPage(page,pageSize);
                List<CommentVO> time=commentMapper.listByArticleIdTime(article_id);
                //追加新数据
                for (CommentVO commentVO:like) {
                    //赞的排序set
                    redisTemplate.opsForZSet().add(key+":commentLike",""+commentVO.getCommentId(),commentVO.getLikeNum());
                    //将评论信息分为固定的和点赞数回复数，方便增改
                    Map<String,Object> map=new HashMap<>();
                    //获取评论人信息
                    UserSimpleVO simpleVO=dubboUserDetails.selectUserCommentVOByUserId(commentVO.getCommenterId());
                    commentVO.setNickname(simpleVO.getNickname());
                    commentVO.setAvatar(simpleVO.getAvatar());
                    map.put("commentInfo",JSON.toJSON(commentVO));
                    map.put("likes",commentVO.getLikeNum());
                    map.put("replys",commentVO.getReplayNum());
                    redisTemplate.opsForHash().putAll(key+":commentDetail:"+commentVO.getCommentId(),map);
                }
                for (CommentVO commentVO:time) {
                    //时间的排序set
                    double commentTime= FormUtils.parseTimeByLocalDateTime(commentVO.getCommontTime());
                    redisTemplate.opsForZSet().add(key+":commentTime",""+commentVO.getCommentId(),commentTime);
                    //将评论信息分为固定的和点赞数回复数，方便增改
                    Map<String,Object> map=new HashMap<>();
                    //获取评论人信息
                    UserSimpleVO simpleVO=dubboUserDetails.selectUserCommentVOByUserId(commentVO.getCommenterId());
                    commentVO.setNickname(simpleVO.getNickname());
                    commentVO.setAvatar(simpleVO.getAvatar());
                    map.put("commentInfo",JSON.toJSON(commentVO));
                    map.put("likes",commentVO.getLikeNum());
                    map.put("replys",commentVO.getReplayNum());
                    redisTemplate.opsForHash().putAll(key+":commentDetail:"+commentVO.getCommentId(),map);
                }
            }
            //返回排序好的commentvo
            Set<String> list;
            if (MODEL.equals(model)){
                //获取点赞排序
                list= redisTemplate.opsForZSet().reverseRange(key+":commentLike",0,page*pageSize-1);
            }else{
                //获取时间排序
                list = redisTemplate.opsForZSet().reverseRange(key+":commentTime",0,page*pageSize-1);
            }
            //获取具体信息
            for (String id:list){
                CommentVO commentVO=JSON.parseObject(redisTemplate.opsForHash().get(key+":commentDetail:","commentInfo").toString(),CommentVO.class);
                commentVO.setLikeNum((Integer) redisTemplate.opsForHash().get(key+":commentDetail:"+id,"likes"));
                commentVO.setReplayNum((Integer) redisTemplate.opsForHash().get(key+":commentDetail:"+id,"replys"));
                commentVOS.add(commentVO);
            }
            return commentVOS;
        }else{
            //没有缓存
            //查询新数据
            PageHelper.startPage(1,pageSize*page);
            List<CommentVO> like=commentMapper.listByArticleIdLike(article_id);
            PageHelper.startPage(1,pageSize*page);
            List<CommentVO> time=commentMapper.listByArticleIdTime(article_id);
            for (CommentVO commentVO:like) {
                //赞的排序set
                redisTemplate.opsForZSet().add(key+":commentLike",""+commentVO.getCommentId(),commentVO.getLikeNum());
                //将评论信息分为固定的和点赞数回复数，方便增改
                Map<String,Object> map=new HashMap<>();
                //获取评论人信息
                UserSimpleVO simpleVO=dubboUserDetails.selectUserCommentVOByUserId(commentVO.getCommenterId());
                commentVO.setNickname(simpleVO.getNickname());
                commentVO.setAvatar(simpleVO.getAvatar());
                map.put("commentInfo",JSON.toJSON(commentVO));
                map.put("likes",commentVO.getLikeNum());
                map.put("replys",commentVO.getReplayNum());
                redisTemplate.opsForHash().putAll(key+":commentDetail:"+commentVO.getCommentId(),map);
            }
            for (CommentVO commentVO:time) {
                //时间的排序set
                double commentTime= FormUtils.parseTimeByLocalDateTime(commentVO.getCommontTime());
                redisTemplate.opsForZSet().add(key+":commentTime",""+commentVO.getCommentId(),commentTime);
                //将评论信息分为固定的和点赞数回复数，方便增改
                Map<String,Object> map=new HashMap<>();
                //获取评论人信息
                UserSimpleVO simpleVO=dubboUserDetails.selectUserCommentVOByUserId(commentVO.getCommenterId());
                commentVO.setNickname(simpleVO.getNickname());
                commentVO.setAvatar(simpleVO.getAvatar());
                map.put("commentInfo",JSON.toJSON(commentVO));
                map.put("likes",commentVO.getLikeNum());
                map.put("replys",commentVO.getReplayNum());
                redisTemplate.opsForHash().putAll(key+":commentDetail:"+commentVO.getCommentId(),map);
            }
            //存完缓存后
            Set<String> list;
            if (MODEL.equals(model)){
                //获取按赞排好序的
                list= redisTemplate.opsForZSet().reverseRange(key+":commentLike",0,page*pageSize-1);
            }else{
                //获取按时间排好序的
                list = redisTemplate.opsForZSet().reverseRange(key+":commentTime",0,page*pageSize-1);
            }
            for (String id:list){
                System.out.println(id);
                System.out.println(redisTemplate.opsForHash().hasKey(key+":commentDetail:"+id,"commentInfo"));
                CommentVO commentVO=JSON.parseObject(redisTemplate.opsForHash().get(key+":commentDetail:"+id,"commentInfo").toString(),CommentVO.class);
                commentVO.setLikeNum((Integer) redisTemplate.opsForHash().get(key+":commentDetail:"+id,"likes"));
                commentVO.setReplayNum((Integer) redisTemplate.opsForHash().get(key+":commentDetail:"+id,"replys"));
                commentVOS.add(commentVO);
            }
            return commentVOS;
        }
    }

    /**
     * 添加新评论
     * @param commentDTO
     */
    @Override
    public void addNew(CommentDTO commentDTO) {
        //访问redis查看用户是否短时间内重复评论该贴
        String key= RedisConstants.ARTICLE_COMMENT+commentDTO.getArticleId()+":user:"+commentDTO.getCommenterId();
        if (redisTemplate.hasKey(key)){
            //存在就说明，用户频繁操作需要提醒
            throw new TimeyanServiceException(ResponseCode.ERR_UNKNOWN,"您评论的太快了，请等3分钟后再进行评论哟");
        }
        Comment comment=new Comment();
        BeanUtils.copyProperties(commentDTO, comment);
        //判断评论人和受评论人是否为一个人
        if (commentDTO.getByCommentId().equals(commentDTO.getCommenterId()))comment.setIsAuthor("1");
        else comment.setIsAuthor("0");
        String articleKey="article:"+commentDTO.getArticleId();
        int lines=commentMapper.addNewComment(comment);
        int rows=0;
        if(redisTemplate.hasKey(articleKey)){
            //有缓存，该评论回复数加一
            redisTemplate.opsForHash().increment(articleKey,"comment",1);
            rows=1;
        }else{
            //否则去修改数据库
            rows=articleMapper.updateCommentByCommentId(commentDTO.getArticleId());
        }
        //未频繁评论
        if (lines<1||rows<1){
            throw new TimeyanServiceException(ResponseCode.ERR_UNKNOWN,"系统繁忙，评论失败，请稍后重试");
        }
        //存过后保留记号,1分钟
        redisTemplate.opsForValue().set(key,1,1, TimeUnit.MINUTES);
    }
}
